/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
 *
 */
import * as path from 'path';

import { hvigorCore, Module } from '@ohos/hvigor';
import fse from 'fs-extra';

import { findTargetProduct } from '../common/find-target-product.js';
import { projectOhosConfigManager } from '../common/global/project-ohos-config-manager.js';
import { BuildModeConst } from '../const/build-mode-const.js';
import { BundleType } from '../const/common-const.js';
import { ApiVersion } from '../const/sdk-const.js';
import { ProjectModel } from '../model/project/project-model.js';
import { AppOpt } from '../options/build/app-ohos-config.js';
import { ProjectBuildProfile } from '../options/build/project-build-profile.js';
import { FormConfigJson } from '../options/configure/form-json-options.js';
import { StartupOptions } from '../options/configure/startup-options.js';
import { TaskNames } from '../tasks/common/task-names.js';
import { ModuleTargetData } from '../tasks/data/hap-task-target-data.js';
import { LegacyCompileResource } from '../tasks/legacy-tasks/legacy-compile-resource.js';
import { LegacyPreviewCompileResource } from '../tasks/legacy-tasks/legacy-preview-compile-resource.js';
import { LegacyProcessResourceIncrement } from '../tasks/legacy-tasks/legacy-process-resource-increment.js';
import { LegacyProcessResource } from '../tasks/legacy-tasks/legacy-process-resource.js';
import { ModuleTaskService } from '../tasks/service/module-task-service.js';
import { ProjectTaskService } from '../tasks/service/project-task-service.js';
import { TargetTaskService } from '../tasks/service/target-task-service.js';
import { HarTargetUtil } from './har-target-util.js';
import { getJson5Obj } from './json-util.js';
import { OhosLogger } from './log/ohos-logger.js';

export const resolveHookDependency = (name: string, target: string) => {
  return `${target}@${name}`;
};

export const dynamicResolveResourceTasks = (service: TargetTaskService, module: Module) => {
  const moduleTaskService: ModuleTaskService = service.getModuleService();
  const moduleType = moduleTaskService.getModuleModel().getModuleType();
  const relatedEntryModules = moduleTaskService.getRelatedEntryModules();
  if (ModuleTaskService.checkEntryModules(moduleType, relatedEntryModules)) {
    for (const entryName of relatedEntryModules!) {
      legacyResourceTask(service, module, entryName);
    }
  }
  legacyResourceTask(service, module);
};

const legacyResourceTask = (service: TargetTaskService, module: Module, entry?: string) => {
  const previewProcessResource: LegacyProcessResourceIncrement = new LegacyProcessResourceIncrement(service, entry);
  const previewCompileResource = new LegacyPreviewCompileResource(service, entry);
  previewCompileResource.declareDepends(previewProcessResource);
  module.registry(previewProcessResource);
  module.registry(previewCompileResource);
  const processResourceTask = new LegacyProcessResource(service, entry);
  const compileResource: LegacyCompileResource = new LegacyCompileResource(service, entry);
  compileResource.declareDepends(processResourceTask);
  module.registry(processResourceTask);
  module.registry(compileResource);
};

export const warnCreateBuildProfileTask = (targetData: ModuleTargetData, targetService: TargetTaskService, log: OhosLogger) => {
  const apiVersion = targetData.getCompileApiVersion();
  const buildProfileFields = targetService.getBuildProfileFields();
  if (apiVersion === ApiVersion.API_VERSION_9) {
    if (buildProfileFields !== undefined) {
      log.warn('Field "buildProfileFields" is not supported in API version 9' + '. The value of this field will be ignored.');
    }
  }
};

/**
 * 判断当前apiVersion是否高于limitApiVersion
 *
 * @param targetData
 * @param limitApiVersion
 */
export const limitMinApiVersion = (targetData: ModuleTargetData, limitApiVersion: number): boolean => {
  const compileApiVersion = targetData.getCompileApiVersion();
  const compatibleApiVersion = targetData.getCompatibleApiVersion();
  return compileApiVersion > limitApiVersion && compatibleApiVersion > limitApiVersion;
};

/**
 * 重新加载依赖
 *
 * @param targetService
 *
 */
export const declareReloadDepends = (targetService: TargetTaskService): string[] => {
  const apiGreaterThan9 = limitMinApiVersion(targetService.getTargetData(), ApiVersion.API_VERSION_9);
  const depends: string[] = ['buildHotReloadResource'];
  if (apiGreaterThan9) {
    depends.push(`${targetService.getTargetData().getTargetName()}@${TaskNames.CommonTask.CREATE_BUILD_PROFILE.name}`);
    // 如果hap/hsp引用了本地har模块则额外调用har模块的CREATE_HAR_BUILD_PROFILE任务用于生成BuildProfile.ets文件
    const depHarTargets = HarTargetUtil.calDepHarTargets(targetService);
    depHarTargets.forEach((targetName, harName) => depends.push(`${harName}:${targetName}@${TaskNames.CommonTask.CREATE_HAR_BUILD_PROFILE.name}`));
  }
  return depends;
};

/**
 * 获取当前buildModeName
 */
export const getBuildModeName = (): string => {
  const cliBuildMode = hvigorCore.getExtraConfig().get('buildMode');
  if (cliBuildMode) {
    return cliBuildMode;
  }

  // 兼容性处理，命令行中没有buildMode时，assembleApp任务会将buildMode强制设置成release
  if (hvigorCore.isCommandEntryTask(TaskNames.CommonHookTask.ASSEMBLE_APP.name)) {
    return BuildModeConst.RELEASE;
  }
  return BuildModeConst.DEBUG;
};

/**
 * 判断是否需要编译卡片
 * @param formJsonPathArr
 */
export const shouldCompileArkTsWidget = (formJsonPathArr: string[]): boolean => {
  return formJsonPathArr.some((formConfigJson: string) => {
    const formConfigObj: FormConfigJson.FormConfigJsonObj = getJson5Obj(formConfigJson);
    if (!formConfigObj) {
      return false;
    }
    return formConfigObj.forms?.some((formConfig: FormConfigJson.FormConfig) => formConfig.uiSyntax === 'arkts');
  });
};

/**
 * 检测是否开了混淆，没开的话给出warning提示
 * @param targetService
 * @param _log
 */
export const doObfuscationCheck = (targetService: TargetTaskService, _log: OhosLogger): void => {
  if (targetService.isDebug()) {
    return;
  }
  const isObfuscationEnabled = targetService.getBuildOption()?.arkOptions?.obfuscation?.ruleOptions?.enable !== false;
  if (isObfuscationEnabled) {
    return;
  }
  _log.warn(
    `If obfuscation is needed, enable obfuscation settings in this build process; failing to do so may prevent future obfuscation. 
               Properly configure obfuscation rules to avoid runtime issues.`,
  );
};

/**
 * 获取bundleType
 * @param product
 * @param projectModel
 */
export const getBundleType = (product: ProjectBuildProfile.ProductBuildOpt, projectModel: ProjectModel): string => {
  const appOptFromConfig: AppOpt | undefined = projectOhosConfigManager.getOverrides()?.appOpt;
  return appOptFromConfig?.bundleType ?? product.bundleType ?? projectModel.getBundleType();
};

/**
 * 判断是否为元服务工程
 * @param product
 * @param projectModel
 */
export const isAtomicServiceProject = (product: ProjectBuildProfile.ProductBuildOpt, projectModel: ProjectModel) => {
  return getBundleType(product, projectModel) === BundleType.ATOMIC_SERVICE;
};

/**
 * 判断启动框架配置文件中appPreloadHintStartupTasks每一项srcEntry的so文件是否在中间产物libs目录下存在
 * 有一种特殊情况：在processLibs任务中若har模块bundledDependencies为true时不收集其依赖字节码har的so，所以如果当前har模块bundledDependencies为true，
 * 则其所依赖的远程字节码har的so跳过检测
 * @param appStartupPath
 * @param baseNativeLibsPath
 * @param _log
 * @param moduleName
 * @param isBundledDependencies
 * @private
 */
export const checkAppPreloadHintStartupTasksSrcEntry = (appStartupPath:string, baseNativeLibsPath:string, _log:OhosLogger,
  moduleName:string, isBundledDependencies = false) => {
  if (!fse.existsSync(appStartupPath)) {
    return;
  }
  // 从base_native_libs.json中读取所有的so文件
  const baseNativeLibsJson = fse.readJsonSync(baseNativeLibsPath);
  const libsJson = baseNativeLibsJson.libs;
  const libsPaths = Object.keys(libsJson);
  const libsFiles = libsPaths.map((libPath)=>{
    return path.basename(libPath);
  });

  const appStartupConfigOpt: StartupOptions = getJson5Obj(appStartupPath);
  if (appStartupConfigOpt.appPreloadHintStartupTasks === undefined) {
    return;
  }
  appStartupConfigOpt.appPreloadHintStartupTasks.forEach((appPreloadHintStartupTasksObj) => {
    // if两个条件：libsFiles是否包含so，若不包含且当前bundledDependencies为true则检测此so是否是远程字节码har的so
    if (!libsFiles.includes(path.basename(appPreloadHintStartupTasksObj.srcEntry))
      && !(isBundledDependencies && !!appPreloadHintStartupTasksObj.isRemoteByteCodeHar)) {
      _log.printErrorExit(
        'STARTUP_SO_FILE_EXIST',
        [appPreloadHintStartupTasksObj.srcEntry, moduleName, appPreloadHintStartupTasksObj.startupConfigPath],
        [[appPreloadHintStartupTasksObj.srcEntry]]
      );
    }
  });
};

/**
 * Checks if fast build app is enabled for the given service.
 *
 * @param {ModuleTaskService} service - The service to check.
 * @returns {boolean} - Returns true if fast build app is enabled, otherwise false.
 */
export const isFastBuildApp = (service: ModuleTaskService | ProjectTaskService): boolean => {
  const packOptions = findTargetProduct(service.getProjectModel()).buildOption?.packOptions;
  return packOptions?.fastBuildApp && hvigorCore.isCommandEntryTask(TaskNames.CommonHookTask.ASSEMBLE_APP.name) || false;
};
